﻿#include "widget.h"
#include "ui_widget.h"

#include <QDebug>
#include <QTcpSocket>
#include <QNetworkInterface>
#include <QMessageBox>
#include <QTextCodec>


Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setLayout(ui->globle);

    bool sendBtnFlag = false;

    //组件初始化
    //隐藏客户端地址选择
    ui->widget_clientChoose->hide();

    ui->label_show1->setText("本地主机地址");
    ui->label_show2->setText("本地主机端口");
    ui->pushButton_sendBtn->setEnabled(false);
    ui->comboBox_choose->setEditable(false);

//将本地的IPv4地址都显示到选择框
    QList<QHostAddress> addresss = QNetworkInterface::allAddresses();
    for(QHostAddress tmp : addresss){
        if(tmp.protocol() == QAbstractSocket::IPv4Protocol){
            ui->comboBox_show1->addItem(tmp.toString());
        }
    }

}

Widget::~Widget()
{
    delete ui;
}



//服务器端，客户端：
void Widget::on_comboBox_choose_activated(const QString &arg1)
{
    qDebug() << arg1;
//TCP服务器网络编程操作
    if(arg1 == "TCP Server"){
        server = new QTcpServer(this);//创建服务器对象
        connect(server,SIGNAL(newConnection()),this,SLOT(on_newClient_connetion()));//检测是否有新的客户端连接

        //自定义信号与槽
        connect(ui->comboBox_clientChoose,&MyComboBox::on_ComboBox_clicked,this,&Widget::myComboBox_refresh);

        ui->label_show1->setText("本地主机地址");
        ui->label_show2->setText("本地主机端口");
        ui->widget_clientChoose->setHidden(false);
    }else if(arg1 == "UDP"){
        ui->label_show1->setText("本地主机地址");
        ui->label_show2->setText("本地主机端口");
        ui->widget_clientChoose->setHidden(true);
//客户端操作
    }else if(arg1 == "TCP Client"){
        //TCP客户端网络编程操作
        ui->label_show1->setText("本地主机地址");
        ui->label_show2->setText("远程主机地址:端口");
        ui->widget_clientChoose->setHidden(true);

        client = new QTcpSocket(this);

        //客户端读取
        connect(client,SIGNAL(readyRead()),this,SLOT(mRead_Data_From_Server()));
        //客户端检测是否断开
        connect(client,SIGNAL(disconnected()),this,SLOT(Disconnected()));
    }
}

//服务器端、客户端：
//建立连接按钮，做三种情况的处理
void Widget::on_pushButton_OpCl_clicked()
{//打开要检测是否已经建立连接，如果建立不了连接，那就报错，而且按钮还要检测是不是这个程序开启的连接，不是的话UI不变
    //断开不需要这么多检测，直接关闭断开就好，ui布局不用判断直接变

    //按键已经变为打开状态
    if(!sendBtnFlag){
        //TCP服务器端打开操作
        if(ui->comboBox_choose->currentText() == "TCP Server"){
            //QHostAddress addr("172.29.208.1");
            int port = ui->lineEdit_port->text().toInt() ;
            //qDebug() << QHostAddress::Any ;
            //开启失败并且不是此次启动开启的
            if(!server->listen(QHostAddress(ui->comboBox_show1->currentText()),port) && ui->pushButton_OpCl->text() == "打开"){
                qDebug() << "listenError";
                QMessageBox msgBox;
                msgBox.setWindowTitle("创建失败");
                msgBox.setText("端口号被占用");
                msgBox.exec();
                return ;
            }else{//开启成功
                qDebug() << "listenSucess";
                sendBtnFlag = true;
                ui->pushButton_sendBtn->setEnabled(true);
                ui->pushButton_OpCl->setText("断开");
            }
        }//TCP客户端打开操作
        else if(ui->comboBox_choose->currentText() == "TCP Client"){

            QStringList addrPort = ui->lineEdit_port->text().split(':');
            qDebug() << addrPort;

            if(addrPort.count() != 2){
                ui->label_status->setText("创建失败");
                return;
            }

            client->connectToHost(addrPort[0],addrPort[1].toInt());

            timer = new QTimer(this);
            //设置定时器只触发一次
            timer->setSingleShot(true);
            timer->setInterval(5000);
            //qDebug() << client->state();
            connect(timer,SIGNAL(timeout()),this,SLOT(timeOut()));
            connect(client,SIGNAL(connected()),this,SLOT(onConnected()));
            connect(client,SIGNAL(erro(QAbstractSocket::SocketError)),this,SLOT(onError(QAbstractSocket::SocketError)));

            this->setEnabled(false);
            timer->start();

        }//UDP端打开操作
        else if((ui->comboBox_choose->currentText() == "UDP")){

        }
    }
    //按键已经变为关闭状态
    else if(sendBtnFlag){
        //服务器端按下断开
        if(ui->comboBox_choose->currentText() == "TCP Server"){
            QList<QTcpSocket *> tcpsSocketCLients = server->findChildren<QTcpSocket *>();
            for(QTcpSocket* tmp:tcpsSocketCLients){
                tmp->close();
            }
            server->close();
        }//客户端按下断开
        else if(ui->comboBox_choose->currentText() == "TCP Client"){
            ui->comboBox_choose->setEnabled(true);
            ui->textEdit_showText->append("断开连接");
            ui->lineEdit_port->setEnabled(true);
            ui->comboBox_show1->setEnabled(true);
            ui->comboBox_choose->setEditable(true);
            client->close();
        }//UDP按下断开
        else if(ui->comboBox_choose->currentText() == "UDP"){

        }

        //三种情况下当按钮已经按下状态都要做的操作
        sendBtnFlag = false;
        ui->pushButton_sendBtn->setEnabled(false);
        ui->pushButton_OpCl->setText("打开");
    }
}

//服务器端：
  //检测到有新的客户端接入
void Widget::on_newClient_connetion()
{
    qDebug() << "new connetion";
    //hasPendingConnections()是否有新的连接
    if(server->hasPendingConnections()){
        QTcpSocket *connction = server->nextPendingConnection();
        qDebug() << "client Addr:" << connction->peerAddress().toString() << "port:" << connction->peerPort();
        ui->textEdit_showText->append("客户端地址:" +
                                      connction->peerAddress().toString()+
                                      "客户端端口号:" +
                                      QString::number(connction->peerPort())+
                                      "\n");
        //读取socket中的数据
        connect(connction,SIGNAL(readyRead()),this,SLOT(on_readRead_handler()));

        //检测客户端的断开
        //第一种方法
        //connect(connction,SIGNAL(disconnected()),this,SLOT(mdisconnection()));
        //第二种方法
        connect(connction,SIGNAL(stateChanged(QAbstractSocket::SocketState)),
                this,SLOT(mstateChanged(QAbstractSocket::SocketState)));

        //设置新的客户端连接，立马选到新的客户端
        //        ui->comboBox_clientChoose->addItem(QString::number(connction->peerPort()));
        //        ui->comboBox_clientChoose->setCurrentText(QString::number(connction->peerPort()));

    }
}

//服务器端：
//服务器端读取客户端
void Widget::on_readRead_handler()
{
//    QList<QTcpSocket *> tcpsSocketCLients = server->findChildren<QTcpSocket *>();
//    for(QTcpSocket *tmp : tcpsSocketCLients){

//        if(QString::number(tmp->peerPort()) == currentName){
//            tmp->write(gbkBytes);
//        }
//    }

    QTcpSocket *tmpSock = qobject_cast<QTcpSocket *>(sender());//sender捕获信号发送者

    QByteArray revData = tmpSock->readAll();
    //QString revData = QString::fromStdString(tmpSock->readAll().toStdString());

    //设置编码，显示中文
    QTextCodec *tc = QTextCodec::codecForName("GBK");
    QString codecText = tc->toUnicode(revData);

    //qDebug() << cc << revData;

    ui->textEdit_showText->moveCursor(QTextCursor::End);
    ui->textEdit_showText->append("【" +tmpSock->peerAddress().toString()+":"+QString::number(tmpSock->peerPort())+"】"+codecText);
}

//服务器端：
//检测到断开之后进行socket清除，内部处理
void Widget::mdisconnection()
{
    QTcpSocket *tmpSock = qobject_cast<QTcpSocket *>(sender());
    qDebug() << "client close";
    //ui->textEdit_showText->insertPlainText("客户端断开");
    tmpSock->deleteLater();
}

//服务器端：
//server监测客户端状态改变，外部显示
void Widget::mstateChanged(QAbstractSocket::SocketState socketState)
{
    QTcpSocket *tmpSock = qobject_cast<QTcpSocket *>(sender());
    //qDebug() << socketState;
    int tmpIndex;
    switch (socketState) {
    case QAbstractSocket::ClosingState:
    case QAbstractSocket::UnconnectedState:
        ui->textEdit_showText->insertPlainText("客户端断开");
        //客户端断开之后还存在系统中，端口号为0，如果不清理下次连接的话检测不到
        tmpIndex = ui->comboBox_clientChoose->findText(QString::number(tmpSock->peerPort()));
        ui->comboBox_clientChoose->removeItem(tmpIndex);

        tmpSock->deleteLater();
        break;
    case QAbstractSocket::ConnectingState:
    case QAbstractSocket::ConnectedState:
        ui->textEdit_showText->insertPlainText("客户端接入");
        break;
    case QAbstractSocket::HostLookupState:
    case QAbstractSocket::BoundState:
    case QAbstractSocket::ListeningState:
        break;
    }
}

//服务器端：
//客户端地址刷新选择
void Widget::myComboBox_refresh()
{
    ui->comboBox_clientChoose->clear();
    ui->comboBox_clientChoose->addItem("All Connections");
    QList<QTcpSocket *> tcpsSocketCLients = server->findChildren<QTcpSocket *>();

    for(QTcpSocket *tmp : tcpsSocketCLients){
        if(tmp != nullptr)
            if(tmp->peerPort() != 0) //注意客户端先前的状态
                ui->comboBox_clientChoose->addItem(QString::number(tmp->peerPort()));
    }

}

//服务器端，客户端：
//发送
void Widget::on_pushButton_sendBtn_clicked()
{
    //设置发送文本编码格式
    QTextCodec *codec = QTextCodec::codecForName("GBK");
    QByteArray gbkBytes = codec->fromUnicode(ui->textEdit_sendText->toPlainText());

    //服务器发送
    if(ui->comboBox_choose->currentText() == "TCP Server"){
        qDebug() << "ready send";
        QList<QTcpSocket *> tcpsSocketCLients = server->findChildren<QTcpSocket *>();
        if(tcpsSocketCLients.count() == 0){
            QMessageBox msgBox;
            msgBox.setWindowTitle("发送错误");
            msgBox.setText("当前无客户端连接!");
            msgBox.exec();
        }
        //qDebug() << tcpsSocketCLients;
        //全部发送
        //qDebug() <<ui->comboBox_clientChoose->currentText() << childIndex;
        if(ui->comboBox_clientChoose->currentText() != "All Connections"){
            //因为选择框索引为1时对应的socket对象中的对象索引为0，所以-1，但这可能出现问题，比如突然删除时，选择框索引没变，就会越界
            //所以要采取找名字的方式去写入，不能根据找索引
            //tcpsSocketCLients[childIndex-1]->write(gbkBytes);
            //根据名字写入
            QString currentName = ui->comboBox_clientChoose->currentText();
            for(QTcpSocket *tmp : tcpsSocketCLients){
                if(QString::number(tmp->peerPort()) == currentName){
                    tmp->write(gbkBytes);
                }
            }
        }else{
            for(QTcpSocket *tmp : tcpsSocketCLients){
                tmp->write(gbkBytes);
            }
        }
    }
    //客户端发送
    else if(ui->comboBox_choose->currentText() == "TCP Client"){

        client->write(gbkBytes);
    }
    //UDP发送
    else if(ui->comboBox_choose->currentText() == "UDP"){

    }

}

//void Widget::on_comboBox_clientChoose_activated(int index)
//{
//    childIndex = index;

//}

//客户端：
//客户端读取
void Widget::mRead_Data_From_Server()
{
    QByteArray revData = client->readAll();
    QTextCodec *tc = QTextCodec::codecForName("GBK");
    QString codecText = tc->toUnicode(revData);


    ui->textEdit_showText->insertPlainText(codecText);

}

//客户端
//创建连接检测定时器，检测是否能连上，超时执行此槽函数
void Widget::onConnected()
{
        timer->stop();
        //连接
        this->setEnabled(true);
        qDebug() << "clientConnectSucess";
        sendBtnFlag = true;
        ui->comboBox_choose->setEnabled(false);
        ui->pushButton_sendBtn->setEnabled(true);
        ui->pushButton_OpCl->setText("断开");

        ui->textEdit_showText->append("连接成功");
        ui->lineEdit_port->setEnabled(false);
        ui->comboBox_show1->setEnabled(false);
        ui->comboBox_choose->setEditable(false);

        //ui->comboBox_show1->clear();
        qDebug() << client->localAddress().toString() << client->localPort();
        //ui->comboBox_show1->addItem(client->peerAddress().toString()+":"+client->peerPort());

}

//客户端：
//连接错误
void Widget::onError(QAbstractSocket::SocketError error)
{
    qDebug() << "连接错误" << error;
    ui->textEdit_showText->append("连接出错：" + client->errorString());
    this->setEnabled(true);
}

//客户端：
//连接超时
void Widget::timeOut()
{
    ui->textEdit_showText->append("连接超时");
    this->setEnabled(true);
}

//客户端：
//客户端监听服务器端
void Widget::Disconnected()
{
    on_pushButton_OpCl_clicked();
    qDebug() << "server is closed!";
}
